/*
 * Copyright (c) 2014 pkzd/1.0, 颜文泽(robin)
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     1 Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     2 Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include	<stdio.h>
#include	<syscall.h>

int	aflg, cflg, lflg, uflg;

void	do_ls(char *dir);
void	printlong(char *file);
void	modetostr(mode_t mode, char *buf);

int
main(int argc, char *argv[])
{
	int c;

	aflg = cflg = lflg = uflg = 0;
	while(--argc > 0 && (*++argv)[0] == '-'){
		while(c = *++argv[0])
		switch(c){
		case 'a':
			aflg = 1;
			break;
		case 'c':
			cflg = 1;
			break;
		case 'l':
			lflg = 1;	
			break;
		case 'u':
			uflg = 1;
			break;
		default:
			printf("Usage: ls -[aclu] [file ...]\n");
			exit(1);
		}
	}
	if(argc){
		while(*argv)
			do_ls(*argv++);
	}else
		do_ls(".");
	exit(0);
}

void
do_ls(char *dir)
{
	int i, j, fd, cnt;
	struct stat stbuf;
	struct direct dbuf[NDIRENT];

	if((fd = open(dir, O_RDONLY, 0)) == -1){
                printf("Error: cannot open file %s\n", dir);
                return;
        }
	if(fstat(fd, &stbuf) == -1){
		printf("Error: cannot stat file %s\n", dir);
		goto out;
	}
	if(!S_ISDIR(stbuf.st_mode)){
		printf("%s\n", dir);
		goto out; 
	}
        while((cnt = read(fd, dbuf, BLKSIZ)) > 0){
                for(i = 0, j = cnt / sizeof(struct direct); i < j; i++){
                        if(dbuf[i].d_ino){
				if(!aflg && dbuf[i].d_name[0] == '.')
					continue;
				if(lflg){
					printlong(dbuf[i].d_name);
				}else
                                	printf("%s\n", dbuf[i].d_name);
			}
		}
        }
out:
        close(fd);
}

void
printlong(char *file)
{
	char buf[10];
	struct tm *tp;
	struct stat stbuf;

	if(stat(file, &stbuf) == -1){
		printf("Error: stat %s fault\n", file);
		return;
	}
	modetostr(stbuf.st_mode, buf);
	printf("%s ", buf);
	printf("%d ", stbuf.st_nlink);
	printf("%d ", stbuf.st_uid);
	printf("%d ", stbuf.st_gid);
	if(S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode))
		printf("%d,%d\t", MAJOR(stbuf.st_dev), MINOR(stbuf.st_dev));
	else
		printf("%d\t", stbuf.st_size);
	if(cflg){
		tp = gmtime(&stbuf.st_ctime);
		printf("%d.%d.%d %d:%d:%d\t", tp->t_year + 1900, tp->t_mon + 1, tp->t_mday, tp->t_hour + 8, tp->t_min, tp->t_sec);
	}else if(uflg){
		tp = gmtime(&stbuf.st_atime);
		printf("%d.%d.%d %d:%d:%d\t", tp->t_year + 1900, tp->t_mon + 1, tp->t_mday, tp->t_hour + 8, tp->t_min, tp->t_sec);
	}else{
		tp = gmtime(&stbuf.st_mtime);
		printf("%d.%d.%d %d:%d:%d\t", tp->t_year + 1900, tp->t_mon + 1, tp->t_mday, tp->t_hour + 8, tp->t_min, tp->t_sec);
	}
	printf("%s\n", file);
}

void
modetostr(mode_t mode, char *buf)
{
	strcpy(buf, "__________");
	if(S_ISDIR(mode))
		buf[0] = 'd';
	if(S_ISCHR(mode))
		buf[0] = 'c';
	if(S_ISBLK(mode))
		buf[0] = 'b';
	if(S_ISLNK(mode))
		buf[0] = 'l';
	if(S_ISRU(mode))
		buf[1] = 'r';	
	if(S_ISWU(mode))
		buf[2] = 'w';
	if(S_ISXU(mode))
		buf[3] = 'x';
	if(S_ISRG(mode))
		buf[4] = 'r';
	if(S_ISWG(mode))
		buf[5] = 'w';
	if(S_ISXG(mode))
		buf[6] = 'x';
	if(S_ISRO(mode))
		buf[7] = 'r';
	if(S_ISWO(mode))
		buf[8] = 'w';
	if(S_ISXO(mode))
		buf[9] = 'x';
}
